<template>
	<div :style="cpntWrapperStyle">
		<!-- :scale="cpntContainer.stepScale"
			:step="cpntContainer.stepScale" -->
		<Draggable
			v-if="showSet(cpnt)"
			ref="cpntDraggable"
			:disabled="disabledSet"
			:width="cpnt.componentInstance.width"
			:height="cpnt.componentInstance.height"
			:left="computedCpntLeft"
			:top="computedCpntTop"
			@move="handleMove"
			@range="handleRange"
			@over="handleOver"
			@focus="handleFocus"
			@blur="handleBlur">
			<component
				:is="cpntModuleName"
				:id="cpnt.componentInstance.uuid"
				ref="cpntInst"
				:class="cpntModuleClass"
				:base="cpntBase"
				:configuration="cpntConfiguration"
				:data="state.shadowData"
				:children-ref="state.childrenRef"
				:callback-values="state.callbackValues"
				:callback-args="getCallBackArgs(cpnt)"
				:edit="isCpntInEditMode()"
				:actions="getCpntActions(cpnt)"
				:events="getCpntEvents(cpnt)"
				:position-type="cpnt.componentInstance.positionType"
				:left="cpnt.componentInstance.left"
				:top="cpnt.componentInstance.top"
				:width="cpnt.componentInstance.width"
				:height="cpnt.componentInstance.height"
				:on-relative="props.onRelative"
				:emit="getCpntEmit"
				:update-config="getCpntUpdateConfig"
				:theme="getTheme(cpnt)"
				:style="cpntStyle"
				:r-r="state.RR"
				:before-mount-hook="props.propsBeforeMountHook" />
		</Draggable>
		<component
			:is="cpntModuleName"
			v-if="!isCpntInEditMode()"
			:id="cpnt.componentInstance.uuid"
			ref="cpntInst"
			:class="cpntModuleClass"
			:base="cpntBase"
			:configuration="cpntConfiguration"
			:data="state.shadowData"
			:children-ref="state.childrenRef"
			:callback-values="state.callbackValues"
			:callback-args="getCallBackArgs(cpnt)"
			:edit="isCpntInEditMode()"
			:actions="getCpntActions(cpnt)"
			:events="getCpntEvents(cpnt)"
			:position-type="cpnt.componentInstance.positionType"
			:width="cpnt.componentInstance.width"
			:height="cpnt.componentInstance.height"
			:left="computedCpntLeft"
			:top="computedCpntTop"
			:on-relative="onRelative"
			:emit="getCpntEmit"
			:update-config="getCpntUpdateConfig"
			:theme="getTheme(cpnt)"
			:style="cpntStyle"
			:r-r="state.RR"
			:before-mount-hook="propsBeforeMountHook" />
		<template v-for="cpntTreeNode in cpnt.children" :key="cpntTreeNode.uuid">
			<ComponentWrapper
				:ref="cpntContainer.getWrapperRefName(cpntTreeNode)"
				:cpnt="cpntTreeNode"
				:on-relative="onRelative"
				:emit="emit"
				:props-before-mount-hook="beforeMountHook"
				@contextmenu.prevent="cpntFrame.handleContextMenu($event, cpntTreeNode)" />
		</template>
	</div>
</template>

<script lang="ts">
export default {
	name: 'ComponentWrapper'
};
</script>
<script lang="ts" setup>
import {
	onMounted,
	reactive,
	toRefs,
	computed,
	inject,
	ref,
	onBeforeMount,
	getCurrentInstance,
	watch
} from 'vue';
import { ComponentTreeHelper } from '@CIF/ComponentTemplate/componentTree';
import { setPx } from '@CIF/Utils/util';
import Draggable from '../UIComponent/Draggable.vue';
import {
	CPNT_REF_PREFIX_ENUM,
	RUNTIME_CFG_ENUM,
	POSITION_ENUM,
	propsPick
} from '@CIF/Runtime/Global/variable';
import request from '@/utils/request';
import _ from 'lodash';
import { usePrimaryStore } from '@/store';

const renderer: any = inject('renderer');
const cpntFrame: any = inject('cpntFrame');
const cpntContainer: any = inject('cpntContainer');
const store = usePrimaryStore();
const props = defineProps({
	cpnt: {
		type: Object,
		default() {
			return {};
		}
	}, // cpntTreeNode
	onRelative: Function,
	emit: Function,
	propsBeforeMountHook: Function
});
const cpnt = reactive(props.cpnt);
// console.log('00000000000000cpnt', cpnt);

let callbackConfigData: any = {};
const state: any = reactive({
	shadowData: [],
	callbackValues: {},
	callbackConfigData: {},
	RR: request,

	childrenRef: [],

	childrenPosition: [],
	childrenConfig: [],
	childrenData: [],

	childrenContext: []
});
const disabledSet = computed(() => {
	if (!isCpntInEditMode()) {
		return true;
	}
	if (!store.getDragMode) {
		return true;
	}
	return store.getActiveCpntIdArr.indexOf(cpnt.uuid) === -1;
});
const cpntDraggable = ref();
watch(
	() => disabledSet.value,
	(nv) => {
		cpntDraggable.value.setActive(!nv);
	}
);
watch(
	() => cpnt.children,
	(val) => {
		// if (isCpntInEditMode()) {
		// 非生产模式下监听子组件变化，子组件数量变化才刷新引用
		// console.log('2222cpnt update', val);
		const newChildrenRef = val.map((item: any) =>
			// cpntContainer.getCpntWrapperById(item.uuid).exposed.getCpntVueInst()
			{
				return { ...item.componentInstance.definitionRefrence, uuid: item.uuid };
			}
		);
		if (state.childrenRef.length !== newChildrenRef.length) {
			state.childrenRef = newChildrenRef;
		}
		// }
	},
	{ deep: true }
);

const cpntWrapperStyle: any = computed(() => {
	return {
		zIndex: disabledSet.value ? cpnt.zIndex : 99999,
		position: 'absolute'
	};
});
const computedCpntLeft = computed(() => {
	return getCpntLeft(cpnt, store.getContainerSize.width);
});
const computedCpntTop = computed(() => {
	return getCpntTop(cpnt, store.getContainerSize.height);
});
const cpntModuleName = computed(() => {
	return getModuleName(cpnt);
});
const cpntTheme = computed(() => {
	return {
		border: _.get(cpnt, 'componentInstance.theme.border')
	};
});
const cpntModuleClass = computed(() => {
	return cpntTheme.value.border ? 'border' : '';
});
const cpntConfiguration = computed(() => {
	// 只用this.cpnt的话貌似不能监听componentInstance的变化？
	const cloneConfigData = _.cloneDeep(_.get(cpnt.componentInstance, 'configData', []));
	if (_.get(window, 'cif.config.logger.enable', false) === true) {
		console.log(
			'CIF.R.R.ComponentWrapper:computed cpntConfiguration',
			cloneConfigData,
			cpnt.uuid,
			cpnt.componentInstance.definitionRefrence.moduleName
		);
	}
	for (const [path, value] of Object.entries(callbackConfigData)) {
		_.set(cloneConfigData, path, value);
	}
	return cloneConfigData;
});
const cpntBase = computed(() => {
	return {
		name: _.get(cpnt, 'componentInstance.definitionRefrence.name'),
		moduleName: _.get(cpnt, 'componentInstance.definitionRefrence.moduleName'),
		version: _.get(cpnt, 'componentInstance.definitionRefrence.version'),
		cpntType: _.get(cpnt, 'componentInstance.definitionRefrence.cpntType'),
		icon: _.get(cpnt, 'componentInstance.icon')
	};
});
const cpntStyle = computed(() => {
	const style: any = {
		boxSizing: 'border-box',
		position: 'absolute',
		height: setPx(cpnt.componentInstance.height),
		width: setPx(cpnt.componentInstance.width)
	};
	if (!isCpntInEditMode()) {
		style.top = computedCpntTop.value + 'px';
		style.left = computedCpntLeft.value + 'px';
	}
	cpntTheme.value.border && (style.borderImageSource = `url(${cpntTheme.value.border})`);
	return style;
});

// 是否编辑模式，暂时关闭
function isCpntInEditMode() {
	if (renderer.state.cifMode !== RUNTIME_CFG_ENUM.PRODUCTION_MODE) {
		return true;
	}
	return false;
}

function getModuleName(cpnt: any) {
	if (!_.isEmpty(cpnt.componentInstance) && !_.isEmpty(cpnt.componentInstance.definitionRefrence)) {
		console.log(
			'1111组件名称',
			CPNT_REF_PREFIX_ENUM.CPNT_DEF + cpnt.componentInstance.definitionRefrence.moduleName
		);
		return CPNT_REF_PREFIX_ENUM.CPNT_DEF + cpnt.componentInstance.definitionRefrence.moduleName;
	} else {
		return '';
	}
}

function showSet(cpnt: any) {
	if (!isCpntInEditMode()) {
		return false;
	}
	if (getModuleName(cpnt) !== '') {
		return true;
	} else {
		return false;
	}
}

function getCpntActions(cpnt: any) {
	return _.get(cpnt, 'componentInstance.definitionRefrence.actions', []);
}
function getCpntEvents(cpnt: any) {
	return _.get(cpnt, 'componentInstance.definitionRefrence.events', []);
}
function getCpntWidth(cpnt: any) {
	return _.get(cpnt, 'componentInstance.width');
}
function getCpntHeight(cpnt: any) {
	return _.get(cpnt, 'componentInstance.height');
}
function getCpntClass(cpnt: any) {
	return _.get(cpnt, 'componentInstance.height');
}

function getCpntLeft(cpnt: any, windowWidth: any = 0) {
	// 枚举：0（左上）、1（右上）、2（左下）、3（右下）
	let left = _.get(cpnt, 'componentInstance.left', 0);
	switch (`${_.get(cpnt, 'componentInstance.positionType', 0)}`) {
		case '0':
			left = _.get(cpnt, 'componentInstance.left', 0);
			break;
		case '1':
			left = windowWidth - getCpntWidth(cpnt) - _.get(cpnt, 'componentInstance.right', 0);
			break;
		case '2':
			left = _.get(cpnt, 'componentInstance.left', 0);
			break;
		case '3':
			left = windowWidth - getCpntWidth(cpnt) - _.get(cpnt, 'componentInstance.right', 0);
			break;
	}

	_.set(cpnt, 'componentInstance.left', left);
	return left;
}

function getCpntTop(cpnt: any, windowHeight: any = 0) {
	// 枚举：0（左上）、1（右上）、2（左下）、3（右下）
	let top = _.get(cpnt, 'componentInstance.top', 0);
	switch (`${_.get(cpnt, 'componentInstance.positionType', 0)}`) {
		case '0':
			top = _.get(cpnt, 'componentInstance.top', 0);
			break;
		case '1':
			top = _.get(cpnt, 'componentInstance.top', 0);
			break;
		case '2':
			top = windowHeight - getCpntHeight(cpnt) - _.get(cpnt, 'componentInstance.bottom', 0);
			break;
		case '3':
			top = windowHeight - getCpntHeight(cpnt) - _.get(cpnt, 'componentInstance.bottom', 0);
			break;
	}
	_.set(cpnt, 'componentInstance.top', top);
	return top;
}

const cpntInst = ref();
function updateCpntData() {
	state.shadowData = getCpntShadowData();
}
function getCpntShadowData() {
	let cloneData = _.cloneDeep(_.get(cpnt, 'componentInstance.data', []));
	const dataSourceType = _.get(cpnt, 'componentInstance.dataSourceType');
	switch (dataSourceType) {
		case -1: // 内置数据源
			break;
		case 1: {
			// api数据源

			break;
		}
		case 2: // 注册服务数据源
			break;
		case 0: // 静态数据源
		default:
			{
				const dataFormatter = _.get(cpnt, 'componentInstance.dataFormatter');
				if (dataFormatter.active === true) {
					const filterCbVar = _.get(cpnt, 'componentInstance.filterCbVar');
					// 执行数据过滤器
					// 尝试从回调池里取字段值，用来处理filter
					const callbackArgs = store.getCallbackValuesByTargets({
						targets: filterCbVar,
						visitor: _.get(cpnt, 'componentInstance.uuid')
					});
					const filter = new Function('data', 'callbackArgs', _.get(dataFormatter, 'filterFn'));
					// 调用生成好的函数并传入实际参数
					cloneData = filter(cloneData, callbackArgs);
				}
			}
			break;
	}
	// if (_.get(window, "cif.config.logger.enable", false) === true) {
	//   console.log("CIF.R.R.ComponentWrapper:getCpntShadowData", this.cpnt.uuid, this.cpnt.componentInstance.definitionRefrence.moduleName)
	// }
	return cloneData;
}

// 获取对象
// function getDragObj(val) {
// 	return this.$refs[`${this.common.DEAFNAME}${val}`];
// }
const handleMove = _.throttle((event: any) => {
	// console.log('77777event', event);
	const containerHeight = store.getContainerSize.height;
	const containerWidth = store.getContainerSize.width;
	cpnt.componentInstance.top = event.top;
	cpnt.componentInstance.left = event.left;
	cpnt.componentInstance.height = event.height;
	cpnt.componentInstance.width = event.width;
	cpnt.componentInstance.bottom = containerHeight - event.top - event.height;
	cpnt.componentInstance.right = containerWidth - event.left - event.width;
}, 100);
const handleRange = _.throttle((event: any) => {
	const containerHeight = store.getContainerSize.height;
	const containerWidth = store.getContainerSize.width;
	cpnt.componentInstance.top = event.top;
	cpnt.componentInstance.left = event.left;
	cpnt.componentInstance.height = event.height;
	cpnt.componentInstance.width = event.width;
	cpnt.componentInstance.bottom = containerHeight - event.top - event.height;
	cpnt.componentInstance.right = containerWidth - event.left - event.width;
}, 100);

function handleOver(event: any) {
	console.log('handleOver', event);
}
function handleFocus(event: any) {
	console.log('handleFocus', event);
}
function handleBlur(event: any) {
	console.log('handleBlur', event);
}

function getCallBackArgs(cpnt: any) {
	return _.get(cpnt, 'componentInstance.callbackArgs');
}

function getCpntEmit(eventName: any, data: any, componentId: any, filter: any) {
	if (_.get(window, 'cif.config.logger.enable', false) === true) {
		console.log('CIF.R.R.ComponentWrapper:getCpntEmit emit', eventName, data, componentId);
	}
	if (props.emit) {
		props.emit(
			eventName,
			data,
			_.isEmpty(componentId) ? _.get(cpnt, 'componentInstance.uuid') : componentId,
			filter
		);
	}
}
function getCpntVueInst() {
	return cpntInst.value;
}

function updateCallbackValues(callbackTarget: any, callbackValue: any) {
	state.callbackValues[callbackTarget] = _.clone(callbackValue);

	const cloneConfigData = _.cloneDeep(_.get(cpnt, 'componentInstance.configData', []));
	const callbackConfigData = _.cloneDeep(state.callbackConfigData);

	Object.keys(callbackConfigData).forEach((path) => {
		for (const [target, value] of Object.entries(state.callbackValues)) {
			if (_.isEqual(_.get(cloneConfigData, path), target)) {
				callbackConfigData[path] = value;
			}
		}
	});

	state.callbackConfigData = callbackConfigData;
}

function getTheme(cpnt: any) {
	return _.get(cpnt, 'componentInstance.theme');
}

function getCpntUpdateConfig({ id, type, payload }: any) {
	if (_.get(window, 'cif.config.logger.enable', false) === true) {
		console.log('CIF.R.R.ComponentWrapper:getCpntUpdateConfig start updateConfig');
	}
	let cpntTreeNode = cpnt;
	if (!_.isNil(id) && id !== cpnt.uuid) {
		// cpntTreeNode = ComponentTreeHelper.findTreeNodeDetail(cpnt.children, id).cpntTreeNode
		cpntTreeNode = ComponentTreeHelper.findTreeNodeQuick(id);
	}
	if (_.isEmpty(cpntTreeNode)) {
		throw new Error('updateConfig: 未能获取到组件id参数！');
	}
	if (_.isNil(type)) {
		throw new Error('updateConfig: 未提供type参数！');
	}
	// TODO: 还没想明白 actions 和 camera 选项能干什么，暂时屏蔽
	if (['config', 'position', 'data'].findIndex((x) => x === type) === -1) {
		throw new Error('updateConfig: type参数必须为 "config", "position", "data" 其中一种！');
	}
	// if (["config", "position", "data", "actions", "camera"].findIndex((x) => x === type) === -1) {
	//   throw new Error('updateConfig: type参数必须为 "config","data","actions"或"camera"其中一种！')
	// }
	if (_.isNil(payload)) {
		throw new Error('updateConfig: 未提供payload参数！');
	}
	// payload 对象属性
	// path: string 需要更新的 config 属性路径 如['chart', 'component', 'color']
	// value: any 控件属性对应的值
	switch (type) {
		// 更新组件的 configuration 属性, 支持组件在非编辑模式下，也可以支持更新 config 配置，但只在编辑页面才生效。
		case 'config':
			if (_.isArray(payload)) {
				try {
					for (const pl of payload) {
						const instance = _.get(cpntTreeNode, 'componentInstance', {});
						const cloneConfigData = _.cloneDeep(_.get(instance, 'configData'));
						_.set(cloneConfigData, pl.path, pl.value);
						instance.configData = _.merge(_.get(instance, 'configData'), cloneConfigData);
					}
				} catch (e) {
					throw new Error('更新组件 configuration 配置失败');
				}
			} else if (_.isPlainObject(payload)) {
				try {
					const instance = _.get(cpntTreeNode, 'componentInstance', {});
					const cloneConfigData = _.cloneDeep(_.get(instance, 'configData'));
					_.set(cloneConfigData, payload.path, payload.value);
					instance.configData = _.merge(_.get(instance, 'configData'), cloneConfigData);
				} catch (e) {
					throw new Error('更新组件 configuration 配置失败');
				}
				break;
			} else {
				throw new Error(
					'updateConfig: 当type参数为config时，payload参数需要提供格式为{path[], value} | {path[], value}[]的数组或对象类型！'
				);
			}
			break;
		// 更新组件的 configuration 属性, 支持组件在非编辑模式下，也可以支持更新 config 配置，但只在编辑页面才生效。
		case 'position':
			if (_.isPlainObject(payload)) {
				try {
					const instance = reactive(_.get(cpntTreeNode, 'componentInstance', {}));
					const positionData = propsPick(payload, POSITION_ENUM);
					Object.keys(positionData).forEach((key) => {
						instance[key] = positionData[key];
						// if (StorageHelper.get(RUNTIME_CFG_ENUM.CIF_MODE) === RUNTIME_CFG_ENUM.DEV_MODE) {
						// store.setSelectedInstance(instance);
						// }
					});
					// if (_.get(window, "cif.config.logger.enable", false) === true) {
					//   console.log(
					//     "CIF.R.R.ComponentWrapper:getCpntUpdateConfig updateConfig 执行组件位置配置更新操作",
					//     cpntTreeNode.uuid,
					//     type,
					//     payload
					//   )
					// }
				} catch (e) {
					throw new Error('更新组件 configuration 配置失败');
				}
				break;
			} else {
				throw new Error(
					'updateConfig: 当type参数为position时，payload参数需要提供格式为包含height、width、left、top、right、bottom、positionType任意键值的对象类型！'
				);
			}
		// data: 更新组件的 data 静态数据
		case 'data':
			if (!_.isArray(payload)) {
				throw new Error('updateConfig: 当type参数为data时，payload参数需要提供数组类型！');
			}
			_.set(cpntTreeNode, 'componentInstance.data', _.clone(payload));
			cpntContainer.getCpntWrapperById(cpntTreeNode.uuid).updateCpntData();
			// this.updateCpntData()
			// if (StorageHelper.get(RUNTIME_CFG_ENUM.CIF_MODE) === RUNTIME_CFG_ENUM.DEV_MODE) {
			// this.$store.commit("setSelectedInstance", _.get(cpntTreeNode, "componentInstance"))
			// }
			break;
		// actions: 用于动态更新组件的 actions 配置。使用场景为：自定义动作中可能存在一些动态的数据，需要在其他配置项发生变化的时候，需要动态更新，比如场景的镜头数据等。
		case 'actions':
			// if (_.isArray(payload)) {
			//   try {
			//     for (const pl of payload) {
			//       const instance = _.get(cpntTreeNode, "componentInstance", {})
			//       const cloneConfigData = _.cloneDeep(_.get(instance, "configData"))
			//       _.set(cloneConfigData, pl.path, pl.value)
			//       instance.configData = _.merge(_.get(instance, "configData"), cloneConfigData)
			//     }
			//   } catch (e) {
			//     throw new Error(`更新组件 actions 配置失败`)
			//   }
			// } else if (_.isPlainObject(payload)) {
			//   try {
			//     const instance = _.get(cpntTreeNode, "componentInstance", {})
			//     const cloneConfigData = _.cloneDeep(_.get(instance, "configData"))
			//     _.set(cloneConfigData, payload.path, payload.value)
			//     instance.configData = _.merge(_.get(instance, "configData"), cloneConfigData)
			//   } catch (e) {
			//     throw new Error(`更新组件 actions 配置失败`)
			//   }
			//   break
			// } else {
			//   throw new Error(
			//     "updateConfig: 当type参数为actions时，payload参数需要提供格式为{path[], value} | {path[], value}[]的数组或对象类型！"
			//   )
			// }
			break;
		// camera: 该类型是在镜头数据保存的时候才需要用到，一般不是三维的镜头数据使用不上。
		case 'camera':
			// if (!_.isArray(payload) || !_.isPlainObject(payload)) {
			//   return new Error(
			//     "updateConfig: 当type参数为config参数时，payload参数需要提供格式为{path[], value} | {path[], value}[]的数组或对象类型！"
			//   )
			// }
			break;
		default:
			return;
	}
	if (_.get(window, 'cif.config.logger.enable', false) === true) {
		console.log(
			'CIF.R.R.ComponentWrapper:getCpntUpdateConfig finish updateConfig',
			cpntTreeNode.uuid,
			type,
			payload
		);
	}
}

function beforeMountHook(context: any) {
	if (_.get(cpnt, 'children.length', 0) !== 0) {
		state.childrenRef.push(context);
	}
}

onBeforeMount(() => {
	state.childrenRef = [];
	cpntContainer.registerCpntRef(cpnt.uuid, getCurrentInstance());

	// 初始化组件事件监听器
	callbackConfigData = _.get(cpnt, 'componentInstance.callbackConfigData');
	// console.log('000000000callbackConfigData', callbackConfigData);

	updateCpntData();
});
onMounted(() => {});
defineExpose({ ...toRefs(state), getCpntVueInst, updateCallbackValues, updateCpntData });
</script>

<style lang="scss" scoped>
.scene-container {
	width: 100%;
	height: 100%;
}
.border {
	border-width: 30px;
	border-style: solid;
	border-color: transparent;
	border-image-slice: 50%;
	border-image-repeat: no-repeat;
	border-image-width: 10;
}
</style>
